#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <mpi.h>
#include <unistd.h>

char *l_opt_arg;
char* const short_options = "hRL:";
struct option long_options[] ={
  {"help",0,NULL,'h'},
  {"read_in_memory",0,NULL,'R'},
  {"splib",1,NULL,'L'},
  {0,0,0,0},
};
int SIZE_FILE_NAME= 200;

int main( int argc, char* argv[] )
{
 
  //
  //puts(search_options);
  /*MPI*/
  int rank, size;
  MPI_Comm new_comm;
  
  MPI_Init( &argc, &argv );
  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
  MPI_Comm_split( MPI_COMM_WORLD, rank == 0, 0, &new_comm );
  if (rank == 0) 
    master_io( MPI_COMM_WORLD, new_comm, argc, argv);
  else
    slave_io( MPI_COMM_WORLD, new_comm );

  MPI_Finalize( );
  return 0;
}

/* This is the master */
int master_io( MPI_Comm master_comm, MPI_Comm comm,int argc ,char* argv[] )
{
  /*get options*/
  int c;
  char search_options[100];
  char fileNames[1000][SIZE_FILE_NAME];// to store all the file names in the list
  memset(search_options,'\0',sizeof(search_options));
  memset(fileNames,'\0',sizeof(fileNames));
  int fileNum = 0;
  while((c=getopt_long(argc,argv,short_options,long_options,NULL))!= -1){
    switch(c){
    case 'R':
      printf("read_in_memory\n");
      strcat(search_options," -sR");
      break;
    case 'L':
      l_opt_arg = optarg;
      printf("specify splib is %s!\n",l_opt_arg);
      strcat(search_options, " -sL");
      strcat(search_options, l_opt_arg);
      break;
    case 'h':
      printf("Usage:mpiexec -n 5 mpiMS_SpectraSTSearchSimple [-R] -L /path/spectra.splib *.mzXML\n");
      break;
    default:
      printf("invalid parameter: %c\n",c);
    }
    //include <unistd.h>, to find all non-option parameters
    int opt = optind;
    while(opt < argc){
      if (argv[opt][0]!='-'){
        printf("->%s\t",argv[opt]);
	strcpy(fileNames[fileNum],argv[opt]);
        opt ++; fileNum ++;
      }else{
        break;
      }
      printf("\n");
    }
  }

  int        i,j, size;
  char       buf[256];
  MPI_Status status;
  MPI_Comm_size( master_comm, &size );

  /*    balance jobs to each processor   */
  int slaveNum = size - 1;
 
  int blockSize = ( fileNum / slaveNum );
  /* if processor number > task number */
  if (blockSize == 0){
    blockSize = 1;
  }
  char queryList[slaveNum][(blockSize+1)*SIZE_FILE_NAME];
  memset(queryList,'\0',sizeof(queryList));
  i = 0; int k = 0;
  //printf("%d\t%d\n",blockSize,fileNum);
  while (i < fileNum){
    int start = i;
    int end = start + blockSize -1 ;

    if (end < fileNum){
      int j ;
      for (j = start; j <= end; j++ ){
	strcat(queryList[k], " ");
	strcat(queryList[k], fileNames[j]);
      }
      i = end + 1;
      k++;
      if (k >= slaveNum){
	k = 0;
      }
    }else{
      int j;
      for (j = start,k = 0; j < fileNum, k < slaveNum ; j++,k++){
	strcat(queryList[k], " ");
	strcat(queryList[k], fileNames[j]);
      }
      i = fileNum;
    }
  }
  
  //print test jobs number
  for(k = 0; k < slaveNum; k++){
    puts("hello");
    puts(queryList[k]);
  }

  /* send out the command to each processor */
  for (k = 1; k< size; k++){
    char command[10000] = "spectrast ";
    strcat(command,search_options);  
    strcat(command," ");
    strcat(command,queryList[k-1]);
    MPI_Send(command,strlen(command)+1,MPI_CHAR,k,0,master_comm);
  }
  
  for (j=1; j<=2; j++) {
    for (i=1; i<size; i++) {
      MPI_Recv( buf, 256, MPI_CHAR, i, 0, master_comm, &status );
      fputs( buf, stdout );
    }
  }
}

/* This is the slave */
int slave_io( MPI_Comm master_comm, MPI_Comm comm )
{
  char buf[256];
  char command[10000];
  int  rank;
  MPI_Status status;
  MPI_Comm_rank( comm, &rank );
  MPI_Recv(command,10000,MPI_CHAR,0,0,master_comm,&status);
  system(command);
  //puts(command);
  memset(buf,'\0',sizeof(buf));
 
  sprintf( buf, "Hello from slave %d\n", rank );
  MPI_Send( buf, strlen(buf) + 1, MPI_CHAR, 0, 0, master_comm );
    
  sprintf( buf, "Goodbye from slave %d\n", rank );
  MPI_Send( buf, strlen(buf) + 1, MPI_CHAR, 0, 0, master_comm );

  return 0;
}
